// 版权归Go作者所有。保留所有权利。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

package edwards25519

import (
	"crypto/subtle"
)

// 用于可变基、恒定时间标量MUL的动态查找表。
type projLookupTable struct {
	points [8]projCached
}

// 固定基、恒定时间标量MUL的预计算查找表。
type affineLookupTable struct {
	points [8]affineCached
}

// 用于可变基、可变时间标量MUL的动态查找表。
type nafLookupTable5 struct {
	points [8]projCached
}

// 用于固定基数、可变时间标量MUL的预计算查找表。
type nafLookupTable8 struct {
	points [64]affineCached
}

// 构造函数。

// 在运行时构建查找表。快速的
func (v *projLookupTable) FromP3(q *Point) {
	// 目标：v点[i]=（i+1）*Q，即Q，2Q。。。，8Q 
	// 这允许查找-8Q-Q、 0，Q。。。，8Q 
	v.points[0].FromP3(q)
	tmpP3 := Point{}
	tmpP1xP1 := projP1xP1{}
	for i := 0; i < 7; i++ {
		// 计算（i+1）*Q为Q+i*Q，并转换为一个经过编程的
		// 这是不必要的复杂，因为API有明确的
		// 接收器，而不是创建堆栈对象和依赖RVO 
		v.points[i+1].FromP3(tmpP3.fromP1xP1(tmpP1xP1.Add(q, &v.points[i])))
	}
}

// 这不是速度优化；应预先计算固定基表。
func (v *affineLookupTable) FromP3(q *Point) {
	// 目标：v点[i]=（i+1）*Q，即Q，2Q。。。，8Q 
	// 这允许查找-8Q-Q、 0，Q。。。，8Q 
	v.points[0].FromP3(q)
	tmpP3 := Point{}
	tmpP1xP1 := projP1xP1{}
	for i := 0; i < 7; i++ {
		// 计算（i+1）*Q为Q+i*Q并转换为仿射
		v.points[i+1].FromP3(tmpP3.fromP1xP1(tmpP1xP1.AddAffine(q, &v.points[i])))
	}
}

// 在运行时构建一个查找表。快速的
func (v *nafLookupTable5) FromP3(q *Point) {
	// 目标：v点[i]=（2*i+1）*Q，即Q，3Q，5Q。。。，15Q 
	// 这允许查找-15Q-3Q，-Q，0，Q，3Q。。。，15Q 
	v.points[0].FromP3(q)
	q2 := Point{}
	q2.Add(q, q)
	tmpP3 := Point{}
	tmpP1xP1 := projP1xP1{}
	for i := 0; i < 7; i++ {
		v.points[i+1].FromP3(tmpP3.fromP1xP1(tmpP1xP1.Add(&q2, &v.points[i])))
	}
}

// 这不是速度优化；应预先计算固定基表。
func (v *nafLookupTable8) FromP3(q *Point) {
	v.points[0].FromP3(q)
	q2 := Point{}
	q2.Add(q, q)
	tmpP3 := Point{}
	tmpP1xP1 := projP1xP1{}
	for i := 0; i < 63; i++ {
		v.points[i+1].FromP3(tmpP3.fromP1xP1(tmpP1xP1.AddAffine(&q2, &v.points[i])))
	}
}

// 选择器。

// 将dest设置为x*Q，其中-8<=x<=8，时间不变。
func (v *projLookupTable) SelectInto(dest *projCached, x int8) {
	// Compute xabs=|x | 
	xmask := x >> 7
	xabs := uint8((x + xmask) ^ xmask)

	dest.Zero()
	for j := 1; j <= 8; j++ {
		// 如果|x |=j 
		cond := subtle.ConstantTimeByteEq(xabs, uint8(j))
		dest.Select(&v.points[j-1], dest, cond)
	}
	// 现在dest=|x |*Q，有条件地求反得到x*Q 
	dest.CondNeg(int(xmask & 1))
}

// 在固定时间内将dest设置为x*Q，其中-8<=x<=8。
func (v *affineLookupTable) SelectInto(dest *affineCached, x int8) {
	// Compute xabs=|x | 
	xmask := x >> 7
	xabs := uint8((x + xmask) ^ xmask)

	dest.Zero()
	for j := 1; j <= 8; j++ {
		// Set dest=j*Q if |x |=j 
		cond := subtle.ConstantTimeByteEq(xabs, uint8(j))
		dest.Select(&v.points[j-1], dest, cond)
	}
	// Now dest=|x |*Q，有条件地求反得到x*Q 
	dest.CondNeg(int(xmask & 1))
}

// 给定0<x<2^4的奇数x，返回x*Q（在可变时间内）。
func (v *nafLookupTable5) SelectInto(dest *projCached, x int8) {
	*dest = v.points[x/2]
}

// 给定0<x<2^7的奇数x，返回x*Q（在可变时间内）。
func (v *nafLookupTable8) SelectInto(dest *affineCached, x int8) {
	*dest = v.points[x/2]
}
